package services

import (
	"context"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"vala/tools"
)

type PHPService struct {
	ExecFile      string                  // 执行文件
	ProcessPool   []*os.Process           // 进程池
	ProcessStates []chan *os.ProcessState // 进程状态
	Cancel        context.CancelFunc      // 取消
	ConnChan      chan net.Conn           // 连接
	ServerStatus  bool
	QuitNotify chan bool
}

func NewPHPService(execFile string) *PHPService {
	phpService := &PHPService{
		ExecFile:      execFile,
		ProcessStates: make([]chan *os.ProcessState, 1),
		ProcessPool:   make([]*os.Process, 0),
		ConnChan:      make(chan net.Conn),
		ServerStatus:  false,
		QuitNotify: make(chan bool),
	}

	return phpService
}

func (phpService *PHPService) Start() {
	if !phpService.Status() {
		phpService.ProcessPool = phpService.ProcessPool[:0]
		phpService.ProcessStates = phpService.ProcessStates[:0]
		// 运行工作进程
		log.Println("Boot - Start Boot PHP_CGI Process")
		for _, srvAddr := range []string{"0.0.0.0:9001", "0.0.0.0:9002","0.0.0.0:9003", "0.0.0.0:9004"} {
			process, cprocessState := tools.StartProcess(phpService.ExecFile, []string{"-c", "php.ini", "-b", srvAddr})
			phpService.ProcessPool = append(phpService.ProcessPool, process)
			phpService.ProcessStates = append(phpService.ProcessStates, cprocessState)
			log.Printf("Boot - Start Boot Listener Task %s\n", srvAddr)
			go phpService.Task(srvAddr)
		}
		// 运行监听进程
		log.Println("Boot - Start Boot MainServer")
		ctx, cancel := context.WithCancel(context.Background())
		go phpService.server(ctx)

		// 取消
		phpService.Cancel = cancel
	}
}

// 运行监听进程
func (phpService *PHPService) server(ctx context.Context) {
	listener, error := net.Listen("tcp", ":9000")
	if error != nil {
		log.Printf("Server - MainServer Connect Failure %v\n", error)
		return
	}
	defer func() {
		phpService.QuitNotify <- true
		log.Println("Server - Close MainServer Listener")
		listener.Close()
	}()

	// 设置进程状态为运行中
	phpService.ServerStatus = true
	// 监听处理连接
	cxtt, cancel := context.WithCancel(ctx)
	go func(ctx2 context.Context) {
		defer func() {
			log.Println("Server - Quit MainServer Listener")
		}()
		for {
			// 退出进程
			select {
			case <-cxtt.Done():
				return
			default:
			}
			// 接受连接
			conn, err := listener.Accept()
			if err != nil {
				fmt.Printf("Server - MainServer Accept Except:%v \n", err)
				continue
			}
			// 连接信息
			log.Println("Server - Accept Conn Info:", conn.RemoteAddr(), conn.LocalAddr())
			// 分发连接
			phpService.ConnChan <- conn
		}
	}(cxtt)
	// 退出
	<-ctx.Done()
	cancel()
}

// 监听处理任务
func (phpService *PHPService) Task(address string) {
	for {
		select {
		case conn := <-phpService.ConnChan:
			phpService.handle(conn, address)
		}
	}
}

// 处理连接
func (phpService *PHPService) handle(sourceConn net.Conn, address string) {
	defer func() {
		log.Println("Request - Connect Close")
		sourceConn.Close()
	}()

	destConn, err := net.Dial("tcp", address)
	if err != nil {
		log.Printf("Request - Connect %v Failure:%v\n", address, err)
		return
	}
	ExitChan := make(chan bool, 1)
	// 发送数据
	go func(sourceConn net.Conn, destConn net.Conn) {
		_, err := io.Copy(destConn, sourceConn)
		log.Printf("Request - From %v Send Complete: %v\n", address, err)
		ExitChan <- true
	}(sourceConn, destConn)
	// 接收数据
	go func(sourceConn net.Conn, destConn net.Conn) {
		_, err := io.Copy(sourceConn, destConn)
		log.Printf("Request - From %v Receive Complete: %v\n", address, err)
		ExitChan <- true
	}(sourceConn, destConn)
	<-ExitChan
	destConn.Close()
}

// 停止服务
func (phpService *PHPService) Stop() {
	for _, process := range phpService.ProcessPool {
		error := process.Kill()
		if error != nil {
			panic(error)
		}
	}
	phpService.Cancel()
	<-phpService.QuitNotify
	phpService.ServerStatus = false
}

// 查询服务状态
func (phpService *PHPService) Status() bool {
	return phpService.ServerStatus
}

func (phpService *PHPService) Reload() {
	phpService.Stop()
	phpService.Start()
}
